package team.archai.nexus.boot.platform.core.tool;

import team.archai.nexus.boot.platform.basics.vo.BasicsTreeVO;
import team.archai.nexus.boot.tool.BeanUtils;
import team.archai.nexus.boot.tool.Tool;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @program: tiny-dust-boot-build
 * @description: 树形数据构建
 * @author: lishibin
 * @create: 2020-09-19 21:46
 **/
public class TreeBuilder {

    public TreeBuilder() {
        super();
    }

    /**
     * 将一组集合转换为树形结构返回
     *
     * @param treeNodes
     * @param <T>
     * @return 返回树形结构
     */
    public static <T extends BasicsTreeVO<T>> T build(List<T> treeNodes) {
        T root = (T) BeanUtils.instance(BeanUtils.getGenericClass(TreeBuilder.class, 0));
        root.setId(-1L);
        List<T> trees = buildList(treeNodes);
        root.getChildren().addAll(trees);
        return root;
    }

    /**
     * 将一组集合转换为树形结构集合返回
     *
     * @param treeNodes
     * @param <T>
     * @return 返回树形结构集合
     */
    public static <T extends BasicsTreeVO<T>> List<T> buildList(List<T> treeNodes) {
        // 1.取出所有顶级元素  id 为 -1 或者
        List<T> roots = treeNodes.parallelStream()
                .filter(root -> root.getParentId() == -1)
                .collect(Collectors.toList());
        Map<Long, List<T>> childrenListMap = treeNodes.parallelStream()
                .collect(Collectors.groupingBy(T::getParentId));
        //取出父id 不在当前集合中的所有元素放置顶级节点
        Set<Long> treeIds = treeNodes.stream().map(T::getId).collect(Collectors.toSet());
        childrenListMap.forEach((k, v) -> {
            if (!treeIds.contains(k) && k != -1) {
                roots.addAll(v);
            }
        });
        roots.forEach(root -> appendChildren(root, childrenListMap));
        return roots;
    }

    /**
     * 追加子元素
     *
     * @param parent
     * @param childrenListMap
     * @param <T>
     */
    private static <T extends BasicsTreeVO<T>> void appendChildren(T parent, Map<Long, List<T>> childrenListMap) {
        List<T> childrenList = childrenListMap.get(parent.getId());
        if (Tool.isEmpty(childrenList)) {
            // 如果没有子元素 设置 children为null ztree显示模式
            parent.setChildren(null);
            return;
        }
        Integer level = parent.getLevel();
        List<T> trees = parent.getChildren();
        if (Tool.isEmpty(trees)) {
            trees = new ArrayList<>(childrenList);
            parent.setChildren(trees);
        }
        childrenList.forEach(children -> {
            children.setLevel(level + 1);
            appendChildren(children, childrenListMap);
        });
    }

}
